/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package uk.ac.cam.juliet.zedcat.client;

import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.Date;
import java.util.LinkedList;
import javax.imageio.ImageIO;

/**
 *
 * @author Chris
 */
// A handling class for a specific hotspot.
// Receives events, and uses their timestamps to keep track of changes to the frame.
// At each frame, it finds the closest region to the hotspot.
// When frame changes, it adds that distance to a running history.
// The history is then checked for entry and exit events, and fired appropriately.
public class HotspotEvents {

    private LinkedList<Double> distances;
    private LinkedList<Date> frame_times;
    private LinkedList<Region> regions;
    private boolean has_entity;

    private double current_dist;
    private Date current_timing;
    private Region current_region;

    private Configuration _conf;
    private int _id;
    private Pipeline _pipeline;

    // Construct a new HotspotEvents
    public HotspotEvents(Pipeline p, Configuration c, int hotspotID) {
        _pipeline = p;
        _conf = c;
        distances = new LinkedList<Double>();
        frame_times = new LinkedList<Date>();
        regions = new LinkedList<Region>();
        current_timing = new Date(0);
        has_entity = false;
        _id = hotspotID;
    }

    // Clock forwards a frame
    public void clock(Date newtime) {

        // Take the current best distance/region and add to the lists.
        // System.out.println("Clocking. New dist: " + current_dist);
        distances.add(current_dist);
        frame_times.add(current_timing);
        regions.add(current_region);
        // Pop any extraeneous items off of the lists.
        while (distances.size() > _conf.getQuantisePeriod())
            distances.pop();
        while (frame_times.size() > _conf.getQuantisePeriod())
            frame_times.pop();
        while (regions.size() > _conf.getQuantisePeriod())
            regions.pop();

        // Check for events.
        checkForEvents();

        // Move clock forwards and dummy the best distance.
        current_timing = newtime;
        current_dist = 99999;
    }

    // Add a new events relation to this hotspot.
    public void newEvent(Date timestamp, double distance, Region region) {

        if (timestamp.after(current_timing))
          clock(timestamp);

        // If this relation is closer, then record this distance and region as the current best.
        if (distance < current_dist) {
            current_dist = distance;
            current_region = region;
        }
        
    }

    // Get a direction for the distances list and use to generate an event.
    private void checkForEvents() {
        int rcode = DoubleListDirection(distances);
        if (rcode == 1)
            TriggerEntryEvent();
        else if (rcode == -1)
            TriggerExitEvent();
    }


    // Entry event triggered.
    // Upload picture to twitpic and add Sighting to the database.
    private void TriggerEntryEvent() {
      if (!has_entity) {
        has_entity = true;
        try {
            String url = uploadImage(current_region.getFrame().getSourceImage());
            _conf.getDatabase().reportEntry(_id, url);
            _pipeline.appendLine("Entry uploaded and reported.");
        } catch (IOException e) {
            _pipeline.appendLine(e.getMessage());
        }
      }
    };

    // Exit event triggered.
    // Upload picture to twitpic and add Sighting to the database.
    private void TriggerExitEvent() {
        if (has_entity) {
            has_entity = false;
            try {
                String url = uploadImage(regions.getFirst().getFrame().getSourceImage());
                _conf.getDatabase().reportExit(_id, url);
                _pipeline.appendLine("Exit uploaded and reported.");
            } catch (IOException e) {
                _pipeline.appendLine(e.getMessage());
            }
        }
    };

    // Upload a BufferedImage to Twitpic and return a url to its thumb.
    private String uploadImage(BufferedImage bi) throws IOException {
        File f = File.createTempFile("temporary", "jpg");
        ImageIO.write(bi,"jpg", f);
        String url = TwitPic.Upload(f);
        f.delete();
        return url;
    }

    // Return 1 for an entry, 0 for no event, -1 for exit.
    private int DoubleListDirection(LinkedList<Double> ld) {
        int zeros = 0;
        int eventLimit = _conf.getQuantisePeriod() / 2;
        boolean entry = true;

        for (double d : ld) {
          if (d == 0)
            zeros++;
        }

        if (ld.size() < _conf.getQuantisePeriod()) {
          entry = false;
        } else {
          for (int j = _conf.getQuantisePeriod()-1; j >= _conf.getQuantisePeriod() - eventLimit; j--)
            if (ld.get(j) != 0)
              entry = false;
        }

        //System.out.print("Entry: " + (entry ? "true" : "false") + ", zeros: " + zeros + " DATA | ");
        //for (int j = 0; j < _conf.getQuantisePeriod(); j++)
        //  System.out.print(j + ": " + ld.get(j) + ", ");
        //System.out.println();

        // If the only 0 is at the first position, then an exit event is triggered.
        if (ld.getFirst() == 0 && zeros == 1) return -1;
        // If the zeros are all at the end then entry.
        if (entry) return 1;
        // Otherwise it's a blip.
        return 0;
    }

}
